package ca.uvic.group2.server;

import ca.uvic.group2.api.*;
import ca.uvic.group2.api.exceptions.*;
import java.io.*;
import java.math.*;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import org.apache.log4j.*;


/**
 * A simple unbounded connection pool that allows the server to keep
 * track of the open DB Connections used by the thread pool, to ensure
 * that the connections can be closed later on.
 */
public class DBConnectionPool {

    protected static Category debugLog = Logger.getInstance("DBPoolDebug");
    protected static Category perfLog = Logger.getInstance("DBPoolPerf");

    private LinkedList<DBConnection2> openConnections = new LinkedList();
    static private DBConnectionPool instance = new DBConnectionPool();

    private DBConnectionPool() {
    }

    static public DBConnectionPool getInstance() {
        return instance;
    }

    public DBConnection2 acquireConnection() {
        try {
            debugLog.info("Creating pooled DB Connection");
            DBConnection2 conn = new DBConnection2();
            conn.openConnection();
            debugLog.info("Pooled DB Connection is open");

            synchronized (openConnections) {
                openConnections.add(conn);
                debugLog.info("Connection count: " + Integer.toString(openConnections.size()));
            }

            return conn;
        } catch (SQLException err) {
            debugLog.error("acquireConnection error", err);
            return null;
        }
    }

    public void returnConnection(DBConnection2 conn) {
        try {
            debugLog.info("Connection returned to pool.  Closing...");
            conn.closeConnection();
        } catch (SQLException err) {
            debugLog.warn("returnConnection error", err);
        }

        synchronized (openConnections) {
            openConnections.remove(conn);
            debugLog.info("Connection Count: " + Integer.toString(openConnections.size()));
        }
    }

    public void closeAllConnections() {
        debugLog.info("Closing all pooled connections...");
        synchronized (openConnections) {
            int count = 0;
            Iterator<DBConnection2> i = openConnections.iterator();
            while (i.hasNext()) {
                debugLog.info("Closing connection " + Integer.toString(++count));
                try {
                    i.next().closeConnection();
                } catch (SQLException err) {
                    debugLog.warn("closeAllConnections error", err);
                }
            }

            openConnections.clear();
        }
    }
}
